/**
 * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springblade.modules.huikecloud.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springblade.common.constant.CommonConstant;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.SecureUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.huikecloud.entity.Jmeter;
import org.springblade.modules.huikecloud.entity.JmeterNode;
import org.springblade.modules.huikecloud.mapper.JmeterMapper;
import org.springblade.modules.huikecloud.service.IJmeterNodeService;
import org.springblade.modules.huikecloud.service.IJmeterService;
import org.springblade.modules.huikecloud.utils.DateUtils;
import org.springblade.modules.huikecloud.utils.ScriptUtil;
import org.springblade.modules.huikecloud.vo.JmeterVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 *  服务实现类
 *
 * @author Blade
 * @since 2021-08-13
 */
@Service
public class JmeterServiceImpl extends BaseServiceImpl<JmeterMapper, Jmeter> implements IJmeterService {


	@Autowired
	private StringRedisTemplate redisTemplate;

	@Autowired
	private IJmeterNodeService jmeterNodeService;

	@Override
	public IPage<JmeterVO> selectJmeterPage(IPage<JmeterVO> page, JmeterVO jmeter) {
		return page.setRecords(baseMapper.selectJmeterPage(page, jmeter));
	}


	/**
	 * 上传jmx压测文件并更新和压测表
	 * @param file     文件
	 * @return ObjectStat
	 */
	@Override
	public R upload_jmx(MultipartFile file) {
		String fileName = file.getOriginalFilename();
		if (!StringUtils.endsWithIgnoreCase(fileName, ".jmx") ) {
			return R.fail("请上传正确的JMX文件!");
		}
		BladeUser user = SecureUtil.getUser();

		if (user!=null && user.getUserId()!=null){
			try {
				String path = CommonConstant.JMETER_FILE_PATH+ File.separator+user.getUserId();
				File filePath = new File(path);
				if (!filePath.exists()){
					boolean mkdir = filePath.mkdir();
					if (!mkdir){
						return R.fail("压测文件夹创建失败");
					}
				}

				String saveName = DateUtils.getOkDate(new Date(),"yyyyMMddHHmmss");
				file.transferTo(new File(filePath+File.separator+saveName+".jmx"));
				Jmeter jmeter = new Jmeter();
				jmeter.setParentId(0L);
				jmeter.setJmxName(fileName.replace(".jmx",""));
				jmeter.setJmxFileName(saveName+".jmx");
				jmeter.setSaveUrl(path+File.separator);

				return R.status(this.saveOrUpdate(jmeter));
			} catch (IOException e) {
				e.printStackTrace();
				return R.fail("压测文件上传失败");
			}
		}
		return R.fail("压测文件上传失败");
	}

	/**
	 * 执行压测脚本
	 * @param jmeter     文件
	 * @return ObjectStat
	 */
	@Override
	public R run(Jmeter jmeter) {

		BladeUser user = SecureUtil.getUser();
		if (user != null && user.getUserId() != null && jmeter != null) {
			String jmxPath = jmeter.getSaveUrl()+jmeter.getJmxFileName();
//			判断脚本是否存在
			if (new File(jmxPath).exists()) {
				String reportPath = jmeter.getSaveUrl() + DateUtils.getOkDate(new Date(),"yyyyMMdd");

				File report = new File(reportPath);
				if (!report.exists()) {
					boolean mkdir = report.mkdir();
					if (!mkdir) {
                        return R.fail("报告文件创建失败");
					}
				}
//				记录执行的时间信息
				Date date = new Date();
				String reportName = DateUtils.getOkDate(date,"HHmmss");
				jmeter.setUpdateTime(date);
				Jmeter children = new Jmeter();
				children.setCreateTime(date);
				children.setUpdateTime(date);

				if (CommonConstant.allNode==null){
					CommonConstant.allNode=new HashSet<>();
					List<JmeterNode> list = jmeterNodeService.list(Wrappers.<JmeterNode>query().lambda().eq(JmeterNode::getStatus, 1));
					for (JmeterNode node:list ) {
						CommonConstant.allNode.add(node.getNodeIp()+":"+node.getNodePort());
					}
				}
				String nodeUrl="";
				for (String url:CommonConstant.allNode) {
					if (!redisTemplate.hasKey(url)) {
						nodeUrl=url;
						redisTemplate.opsForValue().set(url,"1",120, TimeUnit.SECONDS);
						break;
					}
				}
				if ("".equals(nodeUrl)){
					return R.fail("压力机繁忙，请稍后重试");
				}
                String script = CommonConstant.JMETER_HOME + File.separator + "bin"+ File.separator+"jmeter.sh -n -t "
						+ jmxPath + " -l " + reportPath + File.separator + reportName + File.separator + "报告.jtl -e -o "
						+ reportPath+ File.separator+reportName+" -R " + nodeUrl;
                boolean runShell = ScriptUtil.runShell(script, "执行压测脚本");
//						boolean runShell = true;
                if (runShell) {
//                	更新信息
					this.updateById(jmeter);
                    children.setParentId(jmeter.getId());
                    children.setJmxName(jmeter.getJmxName());
					children.setSaveUrl(reportPath+ File.separator);
                    children.setJmxFileName(jmeter.getJmxFileName());
                    children.setJtlFileName("报告.jtl");
                    children.setReportName(reportName);

					redisTemplate.delete(nodeUrl);
                    this.saveOrUpdate(children);
                    return R.success("压测执行成功");
                }
				redisTemplate.delete(nodeUrl);
				return R.fail("压测执行失败");
			}else return R.fail("压测脚本不存在");
		}
        return R.fail("非法用户");
	}

	/**
	 * 删除本地文件
	 * @param id
	 * @return ObjectStat
	 */
	@Override
	public Boolean deleteFile(Long id) {
		Jmeter jmeter = this.getById(id);
		if (jmeter!=null){
			if (jmeter.getParentId()==0L){
				String script = "rm -rf "+jmeter.getSaveUrl()+jmeter.getJmxFileName();
				return ScriptUtil.runShell(script, "删除压测脚本");
			}else {
				String script = "rm -rf "+jmeter.getSaveUrl();
				return ScriptUtil.runShell(script, "删除压测报告");
			}
		}
		return false;
	}

}
